home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / gfx / misc / gnuplot-3.7src.lha / gnuplot-3.7src / gnuplot-3.7.lha / gnuplot-3.7 / command.c < prev    next >
C/C++ Source or Header  |  1998-12-09  |  40KB  |  1,434 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: command.c,v 1.126 1998/06/22 12:24:48 ddenholm Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - command.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37. /*
  38.  * Changes:
  39.  * 
  40.  * Feb 5, 1992  Jack Veenstra   (veenstra@cs.rochester.edu) Added support to
  41.  * filter data values read from a file through a user-defined function before
  42.  * plotting. The keyword "thru" was added to the "plot" command. Example
  43.  * syntax: f(x) = x / 100 plot "test.data" thru f(x) This example divides all
  44.  * the y values by 100 before plotting. The filter function processes the
  45.  * data before any log-scaling occurs. This capability should be generalized
  46.  * to filter x values as well and a similar feature should be added to the
  47.  * "splot" command.
  48.  * 
  49.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  50.  * Added user-specified bases for log scaling.
  51.  */
  52.  
  53. #include "plot.h"
  54. #include "setshow.h"
  55. #include "fit.h"
  56. #include "binary.h"
  57.  
  58. #if defined(MSDOS) || defined(DOS386)
  59. # ifdef DJGPP
  60. extern char HelpFile[];        /* patch for do_help  - AP */
  61. # endif                /* DJGPP */
  62. # ifdef __TURBOC__
  63. #  ifndef _Windows
  64. extern unsigned _stklen = 16394;    /* increase stack size */
  65. extern char HelpFile[];        /* patch for do_help  - DJL */
  66. #  endif /* _Windows */
  67. # endif /* TURBOC */
  68. #endif /* MSDOS */
  69.  
  70. #ifndef _Windows
  71. # include "help.h"
  72. #else
  73. static int winsystem __PROTO((char *));
  74. #endif /* _Windows */
  75.  
  76. #ifndef STDOUT
  77. # define STDOUT 1
  78. #endif
  79.  
  80. #ifdef _Windows
  81. # include <windows.h>
  82. # ifdef __MSC__
  83. #  include <malloc.h>
  84. # else
  85. #  include <alloc.h>
  86. #  include <dir.h>        /* setdisk() */
  87. # endif                /* !MSC */
  88. # include "win/wgnuplib.h"
  89. extern TW textwin;
  90. extern LPSTR winhelpname;
  91. extern void screen_dump(void);    /* in term/win.trm */
  92. extern int Pause(LPSTR mess);    /* in winmain.c */
  93. #endif /* _Windows */
  94.  
  95. #ifdef _Windows
  96. # define SET_CURSOR_WAIT SetCursor(LoadCursor((HINSTANCE) NULL, IDC_WAIT))
  97. # define SET_CURSOR_ARROW SetCursor(LoadCursor((HINSTANCE) NULL, IDC_ARROW))
  98. #else
  99. # define SET_CURSOR_WAIT /* nought, zilch */
  100. # define SET_CURSOR_ARROW /* nought, zilch */
  101. #endif
  102.  
  103. #ifdef OS2
  104.  /* emx has getcwd, chdir that can handle drive names */
  105. # define chdir  _chdir2
  106. extern int PM_pause(char *);  /* term/pm.trm */
  107. extern int ExecuteMacro(char *, int); /* plot.c */
  108. #endif /* OS2 */
  109.  
  110. #ifdef VMS
  111. int vms_vkid;            /* Virtual keyboard id */
  112. int vms_ktid;            /* key table id, for translating keystrokes */
  113. #endif /* VMS */
  114.  
  115. /* Used by vws.trm */
  116. void replotrequest __PROTO((void));
  117.  
  118.  
  119. /* static prototypes */
  120. static int command __PROTO((void));
  121. static int read_line __PROTO((char *prompt));
  122. static void do_shell __PROTO((void));
  123. static void do_help __PROTO((int toplevel));
  124. static void do_system __PROTO((void));
  125. static int changedir __PROTO((char *path));
  126.  
  127. /* input data, parsing variables */
  128. #ifdef AMIGA_SC_6_1
  129. __far int num_tokens, c_token;
  130. #else
  131. int num_tokens, c_token;
  132. #endif
  133.  
  134. struct lexical_unit *token;
  135. int token_table_size;
  136.  
  137. char *input_line;
  138. int input_line_len;
  139. int inline_num;            /* input line number */
  140.  
  141. struct udft_entry *dummy_func;    /* NULL means no dummy vars active */
  142.  
  143. char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1];    /* current dummy vars */
  144.  
  145.  
  146. /* support for replot command */
  147. char *replot_line;
  148. int plot_token;            /* start of 'plot' command */
  149.  
  150. /* If last plot was a 3d one. */
  151. TBOOLEAN is_3d_plot = FALSE;
  152.  
  153. #define Inc_c_token if (++c_token >= num_tokens)    \
  154.                         int_error ("Syntax error", c_token);
  155.  
  156. /* support for dynamic size of input line */
  157. void extend_input_line()
  158. {
  159.     if (input_line_len == 0) {
  160.     /* first time */
  161.     input_line = gp_alloc(MAX_LINE_LEN, "input_line");
  162.     input_line_len = MAX_LINE_LEN;
  163.     input_line[0] = NUL;
  164.     } else {
  165.     input_line = gp_realloc(input_line, input_line_len + MAX_LINE_LEN, "extend input line");
  166.     input_line_len += MAX_LINE_LEN;
  167.     FPRINTF((stderr, "extending input line to %d chars\n", input_line_len));
  168.     }
  169. }
  170.  
  171.  
  172. void extend_token_table()
  173. {
  174.     if (token_table_size == 0) {
  175.     /* first time */
  176.     token = (struct lexical_unit *) gp_alloc(MAX_TOKENS * sizeof(struct lexical_unit), "token table");
  177.     token_table_size = MAX_TOKENS;
  178.     } else {
  179.     token = gp_realloc(token, (token_table_size + MAX_TOKENS) * sizeof(struct lexical_unit), "extend token table");
  180.     token_table_size += MAX_TOKENS;
  181.     FPRINTF((stderr, "extending token table to %d elements\n", token_table_size));
  182.     }
  183. }
  184.  
  185.  
  186. void init_memory()
  187. {
  188.     extend_input_line();
  189.     extend_token_table();
  190.     replot_line = gp_alloc(1, "string");
  191.     *replot_line = NUL;
  192. }
  193.  
  194.  
  195. int com_line()
  196. {
  197.     if (multiplot) {
  198.     /* calls int_error() if it is not happy */
  199.     term_check_multiplot_okay(interactive);
  200.  
  201.     if (read_line("multiplot> "))
  202.         return (1);
  203.     } else {
  204.     if (read_line(PROMPT))
  205.         return (1);
  206.     }
  207.  
  208.     /* So we can flag any new output: if false at time of error,
  209.      * we reprint the command line before printing caret.
  210.      * TRUE for interactive terminals, since the command line is typed.
  211.      * FALSE for non-terminal stdin, so command line is printed anyway.
  212.      * (DFK 11/89)
  213.      */
  214.     screen_ok = interactive;
  215.  
  216.     if (do_line())
  217.     return (1);
  218.     else
  219.     return (0);
  220. }
  221.  
  222.  
  223. int do_line()
  224. {
  225.     /* Line continuation has already been handled
  226.      * by read_line() */
  227.     char *inlptr = input_line;
  228.  
  229.     /* Skip leading whitespace */
  230.     while (isspace((int)*inlptr))
  231.     inlptr++;
  232.  
  233.     if (inlptr != input_line) {
  234.     /* If there was leading whitespace, copy the actual
  235.      * command string to the front. use memmove() because
  236.      * source and target overlap */
  237.     memmove(input_line,inlptr,strlen(inlptr));
  238.     /* Terminate resulting string */
  239.     input_line[strlen(inlptr)] = NUL;
  240.     }
  241.  
  242.     FPRINTF((stderr, "Input line: \"%s\"\n",input_line));
  243.  
  244.     /* also used in load_file */
  245.     if (is_system(input_line[0])) {
  246.     do_system();
  247.     if (interactive)    /* 3.5 did it unconditionally */
  248.         (void) fputs("!\n", stderr);    /* why do we need this ? */
  249.     return (0);
  250.     }
  251.     num_tokens = scanner(input_line);
  252.     c_token = 0;
  253.     while (c_token < num_tokens) {
  254.     if (command())
  255.         return (1);
  256.     if (c_token < num_tokens) {    /* something after command */
  257.         if (equals(c_token, ";"))
  258.         c_token++;
  259.         else
  260.         int_error("';' expected", c_token);
  261.     }
  262.     }
  263.     return (0);
  264. }
  265.  
  266.  
  267. void define()
  268. {
  269.     register int start_token;    /* the 1st token in the function definition */
  270.     register struct udvt_entry *udv;
  271.     register struct udft_entry *udf;
  272.  
  273.     if (equals(c_token + 1, "(")) {
  274.     /* function ! */
  275.     int dummy_num = 0;
  276.     struct at_type *at_tmp;
  277.     char save_dummy[MAX_NUM_VAR][MAX_ID_LEN + 1];
  278.     memcpy(save_dummy, c_dummy_var, sizeof(save_dummy));
  279.     start_token = c_token;
  280.     do {
  281.         c_token += 2;    /* skip to the next dummy */
  282.         copy_str(c_dummy_var[dummy_num++], c_token, MAX_ID_LEN);
  283.     } while (equals(c_token + 1, ",") && (dummy_num < MAX_NUM_VAR));
  284.     if (equals(c_token + 1, ","))
  285.         int_error("function contains too many parameters", c_token + 2);
  286.     c_token += 3;        /* skip (, dummy, ) and = */
  287.     if (END_OF_COMMAND)
  288.         int_error("function definition expected", c_token);
  289.     udf = dummy_func = add_udf(start_token);
  290.     if ((at_tmp = perm_at()) == (struct at_type *) NULL)
  291.         int_error("not enough memory for function", start_token);
  292.     if (udf->at)        /* already a dynamic a.t. there */
  293.         free((char *) udf->at);    /* so free it first */
  294.     udf->at = at_tmp;    /* before re-assigning it. */
  295.     memcpy(c_dummy_var, save_dummy, sizeof(save_dummy));
  296.     m_capture(&(udf->definition), start_token, c_token - 1);
  297.     dummy_func = NULL;    /* dont let anyone else use our workspace */
  298.     } else {
  299.     /* variable ! */
  300.     start_token = c_token;
  301.     c_token += 2;
  302.     udv = add_udv(start_token);
  303.     (void) const_express(&(udv->udv_value));
  304.     udv->udv_undef = FALSE;
  305.     }
  306. }
  307.  
  308.  
  309. static int command()
  310. {
  311.     FILE *fp;
  312.     int i;
  313.     /* string holding name of save or load file */
  314.     char sv_file[MAX_LINE_LEN + 1];
  315.  
  316.     for (i = 0; i < MAX_NUM_VAR; i++)
  317.     c_dummy_var[i][0] = NUL;    /* no dummy variables */
  318.  
  319.     if (is_definition(c_token))
  320.     define();
  321.     else if (almost_equals(c_token, "h$elp") || equals(c_token, "?")) {
  322.     c_token++;
  323.     do_help(1);
  324.     } else if (equals(c_token, "testtime")) {
  325.     /* given a format and a time string, exercise the time code */
  326.     char format[160], string[160];
  327.     struct tm tm;
  328.     double secs;
  329.     if (isstring(++c_token)) {
  330.         quote_str(format, c_token, 159);
  331.         if (isstring(++c_token)) {
  332.         quote_str(string, c_token++, 159);
  333.         memset(&tm, 0, sizeof(tm));
  334.         gstrptime(string, format, &tm);
  335.         secs = gtimegm(&tm);
  336.         fprintf(stderr, "internal = %f - %d/%d/%d::%d:%d:%d , wday=%d, yday=%d\n",
  337.             secs, tm.tm_mday, tm.tm_mon + 1, tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday, tm.tm_yday);
  338.         memset(&tm, 0, sizeof(tm));
  339.         ggmtime(&tm, secs);
  340.         gstrftime(string, 159, format, secs);
  341.         fprintf(stderr, "convert back \"%s\" - %d/%d/%d::%d:%d:%d , wday=%d, yday=%d\n",
  342.             string, tm.tm_mday, tm.tm_mon + 1, tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday, tm.tm_yday);
  343.         }
  344.     }
  345.     } else if (almost_equals(c_token, "test")) {
  346.     c_token++;
  347.     test_term();
  348.     } else if (almost_equals(c_token, "scr$eendump")) {
  349.     c_token++;
  350. #ifdef _Windows
  351.     screen_dump();
  352. #else
  353.     fputs("screendump not implemented\n", stderr);
  354. #endif
  355.     } else if (almost_equals(c_token, "pa$use")) {
  356.     struct value a;
  357.     int sleep_time, text = 0;
  358.     char buf[MAX_LINE_LEN + 1];
  359.  
  360.     c_token++;
  361.     sleep_time = (int) real(const_express(&a));
  362.     buf[0] = NUL;
  363.     if (!(END_OF_COMMAND)) {
  364.         if (!isstring(c_token))
  365.         int_error("expecting string", c_token);
  366.         else {
  367.         quote_str(buf, c_token, MAX_LINE_LEN);
  368.         ++c_token;
  369. #ifdef _Windows
  370.         if (sleep_time >= 0)
  371. #else
  372. # ifdef OS2
  373.         if (strcmp(term->name, "pm") != 0 || sleep_time >= 0)
  374. # else
  375. #  ifdef MTOS
  376.             if (strcmp(term->name, "mtos") != 0 || sleep_time >= 0)
  377. #  endif /* MTOS */
  378. # endif /* OS2 */
  379. #endif /* _Windows */
  380.             fputs(buf, stderr);
  381.         text = 1;
  382.         }
  383.     }
  384.     if (sleep_time < 0) {
  385. #ifdef _Windows
  386.         if (!Pause(buf))
  387.         bail_to_command_line();
  388. #else
  389. # ifdef OS2
  390.         if (strcmp(term->name, "pm") == 0 && sleep_time < 0) {
  391.         int rc;
  392.         if ((rc = PM_pause(buf)) == 0)
  393.             bail_to_command_line();
  394.         else if (rc == 2) {
  395.             fputs(buf, stderr);
  396.             text = 1;
  397.             (void) fgets(buf, MAX_LINE_LEN, stdin);
  398.         }
  399.         }
  400. # else                /* !OS2 */
  401. #  ifdef _Macintosh
  402.         if (strcmp(term->name, "macintosh") == 0 && sleep_time < 0)
  403.         Pause(sleep_time);
  404. #  else                /* !_Macintosh */
  405. #   ifdef MTOS
  406.         if (strcmp(term->name, "mtos") == 0) {
  407.         int MTOS_pause(char *buf);
  408.         int rc;
  409.         if ((rc = MTOS_pause(buf)) == 0)
  410.             bail_to_command_line();
  411.         else if (rc == 2) {
  412.             fputs(buf, stderr);
  413.             text = 1;
  414.             (void) fgets(buf, MAX_LINE_LEN, stdin);
  415.         }
  416.         } else if (strcmp(term->name, "atari") == 0) {
  417.         char *readline(char *);
  418.         char *line = readline("");
  419.         if (line)
  420.             free(line);
  421.         } else
  422.         (void) fgets(buf, MAX_LINE_LEN, stdin);
  423. #   else            /* !MTOS */
  424. #    ifdef ATARI
  425.         if (strcmp(term->name, "atari") == 0) {
  426.         char *readline(char *);
  427.         char *line = readline("");
  428.         if (line)
  429.             free(line);
  430.         } else
  431.         (void) fgets(buf, MAX_LINE_LEN, stdin);
  432. #    else            /* !ATARI */
  433.         (void) fgets(buf, MAX_LINE_LEN, stdin);
  434.         /* Hold until CR hit. */
  435. #    endif            /* !ATARI */
  436. #   endif            /* !MTOS */
  437. #  endif            /* !_Macintosh */
  438. # endif                /* !OS2 */
  439. #endif
  440.     }
  441.     if (sleep_time > 0)
  442.         GP_SLEEP(sleep_time);
  443.  
  444.     if (text != 0 && sleep_time >= 0)
  445.         fputc('\n', stderr);
  446.     screen_ok = FALSE;
  447.     } else if (almost_equals(c_token, "pr$int")) {
  448.     int need_space = 0;    /* space printed between two expressions only */
  449.     screen_ok = FALSE;
  450.     do {
  451.         ++c_token;
  452.         if (isstring(c_token)) {
  453.         char s[MAX_LINE_LEN];
  454.         quote_str(s, c_token, MAX_LINE_LEN);
  455.         fputs(s, stderr);
  456.         need_space = 0;
  457.         ++c_token;
  458.         } else {
  459.         struct value a;
  460.         (void) const_express(&a);
  461.         if (need_space)
  462.             putc(' ', stderr);
  463.         need_space = 1;
  464.         disp_value(stderr, &a);
  465.         }
  466.     } while (!END_OF_COMMAND && equals(c_token, ","));
  467.  
  468.     (void) putc('\n', stderr);
  469.     } else if (almost_equals(c_token, "fit")) {
  470.     ++c_token;
  471.     do_fit();
  472.     } else if (almost_equals(c_token, "up$date")) {
  473.     char tmps[80];
  474.     char tmps2[80];
  475.     /* Have to initialise tmps2, otherwise
  476.      * update() cannot decide whether a valid
  477.      * filename was given. lh
  478.      */
  479.     tmps2[0] = NUL;
  480.     if (!isstring(++c_token))
  481.         int_error("Parameter filename expected", c_token);
  482.     quote_str(tmps, c_token++, 80);
  483.     if (!(END_OF_COMMAND)) {
  484.         if (!isstring(c_token))
  485.         int_error("New parameter filename expected", c_token);
  486.         else
  487.         quote_str(tmps2, c_token++, 80);
  488.     }
  489.     update(tmps, tmps2);
  490.     } else if (almost_equals(c_token, "p$lot")) {
  491.     plot_token = c_token++;
  492.     SET_CURSOR_WAIT;
  493.     plotrequest();
  494.     SET_CURSOR_ARROW;
  495.     } else if (almost_equals(c_token, "sp$lot")) {
  496.     plot_token = c_token++;
  497.     SET_CURSOR_WAIT;
  498.     plot3drequest();
  499.     SET_CURSOR_ARROW;
  500.     } else if (almost_equals(c_token, "rep$lot")) {
  501.     if (replot_line[0] == NUL)
  502.         int_error("no previous plot", c_token);
  503.     c_token++;
  504.     SET_CURSOR_WAIT;
  505.     replotrequest();
  506.     SET_CURSOR_ARROW;
  507.     } else if (almost_equals(c_token, "se$t"))
  508.     set_command();
  509.     else if (almost_equals(c_token, "res$et"))
  510.     reset_command();
  511.     else if (almost_equals(c_token, "sh$ow"))
  512.     show_command();
  513.     else if (almost_equals(c_token, "cl$ear")) {
  514.     term_start_plot();
  515.  
  516.     if (multiplot && term->fillbox) {
  517.         unsigned int x1 = (unsigned int) (xoffset * term->xmax);
  518.         unsigned int y1 = (unsigned int) (yoffset * term->ymax);
  519.         unsigned int width = (unsigned int) (xsize * term->xmax);
  520.         unsigned int height = (unsigned int) (ysize * term->ymax);
  521.         (*term->fillbox) (0, x1, y1, width, height);
  522.     }
  523.     term_end_plot();
  524.  
  525.     screen_ok = FALSE;
  526.     c_token++;
  527.     } else if (almost_equals(c_token, "she$ll")) {
  528.     do_shell();
  529.     screen_ok = FALSE;
  530.     c_token++;
  531.     } else if (almost_equals(c_token, "sa$ve")) {
  532.     if (almost_equals(++c_token, "f$unctions")) {
  533.         if (!isstring(++c_token))
  534.         int_error("expecting filename", c_token);
  535.         else {
  536.         quote_str(sv_file, c_token, MAX_LINE_LEN);
  537.         save_functions(fopen(sv_file, "w"));
  538.         }
  539.     } else if (almost_equals(c_token, "v$ariables")) {
  540.         if (!isstring(++c_token))
  541.         int_error("expecting filename", c_token);
  542.         else {
  543.         quote_str(sv_file, c_token, MAX_LINE_LEN);
  544.         save_variables(fopen(sv_file, "w"));
  545.         }
  546.     } else if (almost_equals(c_token, "s$et")) {
  547.         if (!isstring(++c_token))
  548.         int_error("expecting filename", c_token);
  549.         else {
  550.         quote_str(sv_file, c_token, MAX_LINE_LEN);
  551.         save_set(fopen(sv_file, "w"));
  552.         }
  553.     } else if (isstring(c_token)) {
  554.         quote_str(sv_file, c_token, MAX_LINE_LEN);
  555.         save_all(fopen(sv_file, "w"));
  556.     } else {
  557.         int_error("filename or keyword 'functions', 'variables', or 'set' expected", c_token);
  558.     }
  559.     c_token++;
  560.     } else if (almost_equals(c_token, "l$oad")) {
  561.     if (!isstring(++c_token))
  562.         int_error("expecting filename", c_token);
  563.     else {
  564.         quote_str(sv_file, c_token, MAX_LINE_LEN);
  565.         /* load_file(fp=fopen(sv_file, "r"), sv_file, FALSE); OLD
  566.          * DBT 10/6/98 handle stdin as special case
  567.          * passes it on to load_file() so that it gets
  568.          * pushed on the stack and recusion will work, etc
  569.          */
  570.         fp = strcmp(sv_file, "-") ? fopen(sv_file, "r") : stdin; 
  571.         load_file(fp, sv_file, FALSE);
  572.         /* input_line[] and token[] now destroyed! */
  573.         c_token = num_tokens = 0;
  574.     }
  575.     } else if (almost_equals(c_token, "ca$ll")) {
  576.     if (!isstring(++c_token))
  577.         int_error("expecting filename", c_token);
  578.     else {
  579.         quote_str(sv_file, c_token, MAX_LINE_LEN);
  580.         load_file(fopen(sv_file, "r"), sv_file, TRUE);    /* Argument list follows filename */
  581.         /* input_line[] and token[] now destroyed! */
  582.         c_token = num_tokens = 0;
  583.     }
  584.     } else if (almost_equals(c_token, "if")) {
  585.     double exprval;
  586.     struct value t;
  587.     if (!equals(++c_token, "("))    /* no expression */
  588.         int_error("expecting (expression)", c_token);
  589.     exprval = real(const_express(&t));
  590.     if (exprval != 0.0) {
  591.         /* fake the condition of a ';' between commands */
  592.         int eolpos = token[num_tokens - 1].start_index + token[num_tokens - 1].length;
  593.         --c_token;
  594.         token[c_token].length = 1;
  595.         token[c_token].start_index = eolpos + 2;
  596.         input_line[eolpos + 2] = ';';
  597.         input_line[eolpos + 3] = NUL;
  598.     } else
  599.         c_token = num_tokens = 0;
  600.     } else if (almost_equals(c_token, "rer$ead")) {
  601.     fp = lf_top();
  602.     if (fp != (FILE *) NULL)
  603.         rewind(fp);
  604.     c_token++;
  605.     } else if (almost_equals(c_token, "cd")) {
  606.     if (!isstring(++c_token))
  607.         int_error("expecting directory name", c_token);
  608.     else {
  609.         quote_str(sv_file, c_token, MAX_LINE_LEN);
  610.         if (changedir(sv_file)) {
  611.         int_error("Can't change to this directory", c_token);
  612.         }
  613.         c_token++;
  614.     }
  615.     } else if (almost_equals(c_token, "pwd")) {
  616.     GP_GETCWD(sv_file, sizeof(sv_file));
  617.     fprintf(stderr, "%s\n", sv_file);
  618.     c_token++;
  619.     } else if (almost_equals(c_token, "ex$it") ||
  620.            almost_equals(c_token, "q$uit")) {
  621.     /* graphics will be tidied up in main */
  622.     return (1);
  623.     } else if (!equals(c_token, ";")) {        /* null statement */
  624. #ifdef OS2
  625.     if (_osmode == OS2_MODE) {
  626.         if (token[c_token].is_token) {
  627.         int rc;
  628.         rc = ExecuteMacro(input_line + token[c_token].start_index,
  629.                   token[c_token].length);
  630.         if (rc == 0) {
  631.             c_token = num_tokens = 0;
  632.             return (0);
  633.         }
  634.         }
  635.     }
  636. #endif
  637.     int_error("invalid command", c_token);
  638.     }
  639.     return (0);
  640. }
  641.  
  642.  
  643. void done(status)
  644. int status;
  645. {
  646.     term_reset();
  647.     exit(status);
  648. }
  649.  
  650. static int changedir(path)
  651. char *path;
  652. {
  653. #if defined(MSDOS) || defined(WIN16) || defined(ATARI) || defined(DOS386)
  654. # if defined(__ZTC__)
  655.     unsigned dummy;        /* it's a parameter needed for dos_setdrive */
  656. # endif
  657.  
  658.     /* first deal with drive letter */
  659.  
  660.     if (isalpha(path[0]) && (path[1] == ':')) {
  661.     int driveno = toupper(path[0]) - 'A';    /* 0=A, 1=B, ... */
  662.  
  663. # if defined(ATARI)
  664.     (void) Dsetdrv(driveno);
  665. # endif
  666.  
  667. # if defined(__ZTC__)
  668.     (void) dos_setdrive(driveno + 1, &dummy);
  669. # endif
  670.  
  671. # if (defined(MSDOS) && defined(__EMX__)) || defined(__MSC__)
  672.     (void) _chdrive(driveno + 1);
  673. # endif
  674.  
  675.  
  676. /* HBB: recent versions of DJGPP also have setdisk():,
  677.  * so I del'ed the special code */
  678. # if ((defined(MSDOS) || defined(_Windows)) && defined(__TURBOC__)) || defined(DJGPP)
  679.     (void) setdisk(driveno);
  680. # endif
  681.     path += 2;        /* move past drive letter */
  682.     }
  683.     /* then change to actual directory */
  684.     if (*path)
  685.     if (chdir(path))
  686.         return 1;
  687.  
  688.     return 0;            /* should report error with setdrive also */
  689.  
  690. #elif defined(WIN32)
  691.     return !(SetCurrentDirectory(path));
  692. #else
  693.     return chdir(path);
  694. #endif /* MSDOS, ATARI etc. */
  695. }
  696.  
  697.  
  698. void replotrequest()
  699. {
  700.     if (equals(c_token, "["))
  701.     int_error("cannot set range with replot", c_token);
  702.  
  703.     /* do not store directly into the replot_line string, until the
  704.      * new plot line has been successfully plotted. This way,
  705.      * if user makes a typo in a replot line, they do not have
  706.      * to start from scratch. The replot_line will be committed
  707.      * after do_plot has returned, whence we know all is well
  708.      */
  709.     if (END_OF_COMMAND) {
  710.     /* it must already be long enough, but lets make sure */
  711.     int len = strlen(replot_line) + 1;
  712.     while (input_line_len < len)
  713.         extend_input_line();
  714.     strcpy(input_line, replot_line);
  715.     } else {
  716.     char *replot_args = NULL;    /* else m_capture will free it */
  717.     int last_token = num_tokens - 1;
  718.     /* length = length of old part + length of new part + ',' + \0 */
  719.     int newlen = strlen(replot_line) + token[last_token].start_index + token[last_token].length - token[c_token].start_index + 2;
  720.     m_capture(&replot_args, c_token, last_token);    /* might be empty */
  721.     while (input_line_len < newlen)
  722.         extend_input_line();
  723.     strcpy(input_line, replot_line);
  724.     strcat(input_line, ",");
  725.     strcat(input_line, replot_args);
  726.     free(replot_args);
  727.     }
  728.     plot_token = 0;        /* whole line to be saved as replot line */
  729.  
  730.     screen_ok = FALSE;
  731.     num_tokens = scanner(input_line);
  732.     c_token = 1;        /* skip the 'plot' part */
  733.     if (is_3d_plot)
  734.     plot3drequest();
  735.     else
  736.     plotrequest();
  737. }
  738.  
  739.  
  740. /* Support for input, shell, and help for various systems */
  741.  
  742. #ifdef VMS
  743.  
  744. # include <descrip.h>
  745. # include <rmsdef.h>
  746. # include <smgdef.h>
  747. # include <smgmsg.h>
  748.  
  749. extern lib$get_input(), lib$put_output();
  750. extern smg$read_composed_line();
  751. extern sys$putmsg();
  752. extern lbr$output_help();
  753. extern lib$spawn();
  754.  
  755. int vms_len;
  756.  
  757. unsigned int status[2] = {1, 0};
  758.  
  759. static char Help[MAX_LINE_LEN+1] = "gnuplot";
  760.  
  761. $DESCRIPTOR(prompt_desc, PROMPT);
  762. /* temporary fix until change to variable length */
  763. struct dsc$descriptor_s line_desc =
  764. {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
  765.  
  766. $DESCRIPTOR(help_desc, Help);
  767. $DESCRIPTOR(helpfile_desc, "GNUPLOT$HELP");
  768.  
  769. /* please note that the vms version of read_line doesn't support variable line
  770.    length (yet) */
  771.  
  772. static int read_line(prompt)
  773. char *prompt;
  774. {
  775.     int more, start = 0;
  776.     char expand_prompt[40];
  777.  
  778.     prompt_desc.dsc$w_length = strlen(prompt);
  779.     prompt_desc.dsc$a_pointer = prompt;
  780.     (void) strcpy(expand_prompt, "_");
  781.     (void) strncat(expand_prompt, prompt, 38);
  782.     do {
  783.     line_desc.dsc$w_length = MAX_LINE_LEN - start;
  784.     line_desc.dsc$a_pointer = &input_line[start];
  785.     switch (status[1] = smg$read_composed_line(&vms_vkid, &vms_ktid, &line_desc, &prompt_desc, &vms_len)) {
  786.     case SMG$_EOF:
  787.         done(IO_SUCCESS);    /* ^Z isn't really an error */
  788.         break;
  789.     case RMS$_TNS:        /* didn't press return in time */
  790.         vms_len--;        /* skip the last character */
  791.         break;        /* and parse anyway */
  792.     case RMS$_BES:        /* Bad Escape Sequence */
  793.     case RMS$_PES:        /* Partial Escape Sequence */
  794.         sys$putmsg(status);
  795.         vms_len = 0;    /* ignore the line */
  796.         break;
  797.     case SS$_NORMAL:
  798.         break;        /* everything's fine */
  799.     default:
  800.         done(status[1]);    /* give the error message */
  801.     }
  802.     start += vms_len;
  803.     input_line[start] = NUL;
  804.     inline_num++;
  805.     if (input_line[start - 1] == '\\') {
  806.         /* Allow for a continuation line. */
  807.         prompt_desc.dsc$w_length = strlen(expand_prompt);
  808.         prompt_desc.dsc$a_pointer = expand_prompt;
  809.         more = 1;
  810.         --start;
  811.     } else {
  812.         line_desc.dsc$w_length = strlen(input_line);
  813.         line_desc.dsc$a_pointer = input_line;
  814.         more = 0;
  815.     }
  816.     } while (more);
  817.     return 0;
  818. }
  819.  
  820.  
  821. # ifdef NO_GIH
  822. static void do_help(toplevel)
  823. int toplevel;            /* not used for VMS version */
  824. {
  825.     int first = c_token;
  826.     while (!END_OF_COMMAND)
  827.     ++c_token;
  828.  
  829.     strcpy(Help, "GNUPLOT ");
  830.     capture(Help + 8, first, c_token - 1, sizeof(Help) - 9);
  831.     help_desc.dsc$w_length = strlen(Help);
  832.     if ((vaxc$errno = lbr$output_help(lib$put_output, 0, &help_desc,
  833.             &helpfile_desc, 0, lib$get_input)) != SS$_NORMAL)
  834.     os_error("can't open GNUPLOT$HELP", NO_CARET);
  835. }
  836.  
  837. # endif /* NO_GIH */
  838.  
  839. static void do_shell()
  840. {
  841.     if ((vaxc$errno = lib$spawn()) != SS$_NORMAL) {
  842.     os_error("spawn error", NO_CARET);
  843.     }
  844. }
  845.  
  846.  
  847. static void do_system()
  848. {
  849. /*    input_line[0] = ' ';    an embarrassment, but... */
  850.  
  851. /* input_line is filled by read_line or load_file, but 
  852.  * line_desc length is set only by read_line; adjust now
  853.  */
  854.     line_desc.dsc$w_length = strlen(input_line) - 1;
  855.     line_desc.dsc$a_pointer = &input_line[1];
  856.  
  857.     if ((vaxc$errno = lib$spawn(&line_desc)) != SS$_NORMAL)
  858.     os_error("spawn error", NO_CARET);
  859.  
  860.     (void) putc('\n', stderr);
  861. }
  862.  
  863. #endif /* VMS */
  864.  
  865.  
  866. #ifdef _Windows
  867.  
  868. # ifdef NO_GIH
  869. static void do_help(toplevel)
  870. int toplevel;            /* not used for windows */
  871. {
  872.     if (END_OF_COMMAND)
  873.     WinHelp(textwin.hWndParent, (LPSTR) winhelpname, HELP_INDEX, (DWORD) NULL);
  874.     else {
  875.     char buf[128];
  876.     int start = c_token++;
  877.     while (!(END_OF_COMMAND))
  878.         c_token++;
  879.     capture(buf, start, c_token - 1, 128);
  880.     WinHelp(textwin.hWndParent, (LPSTR) winhelpname, HELP_PARTIALKEY, (DWORD) buf);
  881.     }
  882. }
  883. # endif /* NO_GIH */
  884. #endif /* _Windows */
  885.  
  886. /*
  887.  * do_help: (not VMS, although it would work) Give help to the user. It
  888.  * parses the command line into helpbuf and supplies help for that string.
  889.  * Then, if there are subtopics available for that key, it prompts the user
  890.  * with this string. If more input is given, do_help is called recursively,
  891.  * with argument 0.  Thus a more specific help can be supplied. This can be 
  892.  * done repeatedly.  If null input is given, the function returns, effecting 
  893.  * a backward climb up the tree.
  894.  * David Kotz (David.Kotz@Dartmouth.edu) 10/89
  895.  * drd - The help buffer is first cleared when called with toplevel=1. 
  896.  * This is to fix a bug where help is broken if ^C is pressed whilst in the 
  897.  * help.
  898.  */
  899.  
  900. #ifndef NO_GIH
  901. static void do_help(toplevel)
  902. int toplevel;
  903. {
  904.     static char *helpbuf = NULL;
  905.     static char *prompt = NULL;
  906.     int base;            /* index of first char AFTER help string */
  907.     int len;            /* length of current help string */
  908.     TBOOLEAN more_help;
  909.     TBOOLEAN only;        /* TRUE if only printing subtopics */
  910.     int subtopics;        /* 0 if no subtopics for this topic */
  911.     int start;            /* starting token of help string */
  912.     char *help_ptr;        /* name of help file */
  913. # if defined(SHELFIND)
  914.     static char help_fname[256] = ""; /* keep helpfilename across calls */
  915. # endif
  916.  
  917. # if defined(MTOS) || defined(ATARI)
  918.     char const *const ext[] = {NULL};
  919. # endif
  920.  
  921.     if ((help_ptr = getenv("GNUHELP")) == (char *) NULL)
  922. # ifndef SHELFIND
  923.     /* if can't find environment variable then just use HELPFILE */
  924.  
  925. /* patch by David J. Liu for getting GNUHELP from home directory */
  926. #  if (defined(__TURBOC__) && (defined(MSDOS) || defined(DOS386))) || defined(__DJGPP__)
  927.     help_ptr = HelpFile;
  928. #  else
  929. #   if defined(MTOS) || defined(ATARI)
  930.     {
  931.     if ((help_ptr = findfile(HELPFILE, getenv("GNUPLOTPATH"), ext)) == NULL)
  932.         help_ptr = findfile(HELPFILE, getenv("PATH"), ext);
  933.     if (!help_ptr)
  934.         help_ptr = HELPFILE;
  935.     }
  936. #   else
  937.     help_ptr = HELPFILE;
  938. #   endif /* MTOS || ATARI */
  939. #  endif /* __TURBOC__ */
  940. /* end of patch  - DJL */
  941.  
  942. # else /* !SHELFIND */
  943.     /* try whether we can find the helpfile via shell_find. If not, just
  944.        use the default. (tnx Andreas) */
  945.  
  946.     if (!strchr(HELPFILE, ':') && !strchr(HELPFILE, '/') &&
  947.         !strchr(HELPFILE, '\\')) {
  948.         if (strlen(help_fname) == 0) {
  949.         strcpy(help_fname, HELPFILE);
  950.         if (shel_find(help_fname) == 0) {
  951.             strcpy(help_fname, HELPFILE);
  952.         }
  953.         }
  954.         help_ptr = help_fname;
  955.     } else {
  956.         help_ptr = HELPFILE;
  957.     }
  958. # endif /* !SHELFIND */
  959.  
  960.     /* Since MSDOS DGROUP segment is being overflowed we can not allow such  */
  961.     /* huge static variables (1k each). Instead we dynamically allocate them */
  962.     /* on the first call to this function...                                 */
  963.     if (helpbuf == NULL) {
  964.     helpbuf = gp_alloc((unsigned long) MAX_LINE_LEN, "help buffer");
  965.     prompt = gp_alloc((unsigned long) MAX_LINE_LEN, "help prompt");
  966.     helpbuf[0] = prompt[0] = 0;
  967.     }
  968.     if (toplevel)
  969.     helpbuf[0] = prompt[0] = 0;    /* in case user hit ^c last time */
  970.  
  971.     len = base = strlen(helpbuf);
  972.  
  973.     /* find the end of the help command */
  974.     for (start = c_token; !(END_OF_COMMAND); c_token++);
  975.     /* copy new help input into helpbuf */
  976.     if (len > 0)
  977.     helpbuf[len++] = ' ';    /* add a space */
  978.     capture(helpbuf + len, start, c_token - 1, MAX_LINE_LEN - len);
  979.     squash_spaces(helpbuf + base);    /* only bother with new stuff */
  980.     lower_case(helpbuf + base);    /* only bother with new stuff */
  981.     len = strlen(helpbuf);
  982.  
  983.     /* now, a lone ? will print subtopics only */
  984.     if (strcmp(helpbuf + (base ? base + 1 : 0), "?") == 0) {
  985.     /* subtopics only */
  986.     subtopics = 1;
  987.     only = TRUE;
  988.     helpbuf[base] = NUL;    /* cut off question mark */
  989.     } else {
  990.     /* normal help request */
  991.     subtopics = 0;
  992.     only = FALSE;
  993.     }
  994.  
  995.     switch (help(helpbuf, help_ptr, &subtopics)) {
  996.     case H_FOUND:{
  997.         /* already printed the help info */
  998.         /* subtopics now is true if there were any subtopics */
  999.         screen_ok = FALSE;
  1000.  
  1001.         do {
  1002.         if (subtopics && !only) {
  1003.             /* prompt for subtopic with current help string */
  1004.             if (len > 0)
  1005.             (void) sprintf(prompt, "Subtopic of %s: ", helpbuf);
  1006.             else
  1007.             (void) strcpy(prompt, "Help topic: ");
  1008.             read_line(prompt);
  1009.             num_tokens = scanner(input_line);
  1010.             c_token = 0;
  1011.             more_help = !(END_OF_COMMAND);
  1012.             if (more_help)
  1013.             /* base for next level is all of current helpbuf */
  1014.             do_help(0);
  1015.         } else
  1016.             more_help = FALSE;
  1017.         } while (more_help);
  1018.  
  1019.         break;
  1020.     }
  1021.     case H_NOTFOUND:{
  1022.         printf("Sorry, no help for '%s'\n", helpbuf);
  1023.         break;
  1024.     }
  1025.     case H_ERROR:{
  1026.         perror(help_ptr);
  1027.         break;
  1028.     }
  1029.     default:{            /* defensive programming */
  1030.         int_error("Impossible case in switch", NO_CARET);
  1031.         /* NOTREACHED */
  1032.     }
  1033.     }
  1034.  
  1035.     helpbuf[base] = NUL;    /* cut it off where we started */
  1036. }
  1037. #endif /* !NO_GIH */
  1038.  
  1039.  
  1040. #ifndef VMS
  1041.  
  1042. # ifdef AMIGA_AC_5
  1043. static char *parms[80];
  1044. static char strg0[256];
  1045. static void getparms __PROTO((char *, char**));
  1046. # endif
  1047.  
  1048. static void do_system()
  1049. {
  1050. # ifdef AMIGA_AC_5
  1051.     getparms(input_line + 1, parms);
  1052.     fexecv(parms[0], parms);
  1053. # elif (defined(ATARI) && defined(__GNUC__))
  1054. /* || (defined(MTOS) && defined(__GNUC__)) */
  1055.     /* use preloaded shell, if available */
  1056.     short (*shell_p) (char *command);
  1057.     void *ssp;
  1058.  
  1059.     ssp = (void *) Super(NULL);
  1060.     shell_p = *(short (**)(char *)) 0x4f6;
  1061.     Super(ssp);
  1062.  
  1063.     /* this is a bit strange, but we have to have a single if */
  1064.     if (shell_p)
  1065.     (*shell_p) (input_line + 1);
  1066.     else
  1067.     system(input_line + 1);
  1068. # elif defined(_Windows)
  1069.     winsystem(input_line + 1);
  1070. # else /* !(AMIGA_AC_5 || ATARI && __GNUC__ || _Windows) */
  1071. /* (am, 19980929)
  1072.  * OS/2 related note: cmd.exe returns 255 if called w/o argument.
  1073.  * i.e. calling a shell by "!" will always end with an error message.
  1074.  * A workaround has to include checking for EMX,OS/2, two environment
  1075.  *  variables,...
  1076.  */
  1077.     system(input_line + 1);
  1078. # endif /* !(AMIGA_AC_5 || ATARI&&__GNUC__ || _Windows) */
  1079. }
  1080.  
  1081.  
  1082. # ifdef AMIGA_AC_5
  1083. /******************************************************************************
  1084.  * Parses the command string (for fexecv use) and  converts the first token
  1085.  * to lower case                                                 
  1086.  *****************************************************************************/
  1087. static void getparms(command, parms)
  1088. char *command;
  1089. char **parms;
  1090. {
  1091.     register int i = 0;        /* A bunch of indices */
  1092.     register int j = 0;
  1093.     register int k = 0;
  1094.  
  1095.     while (*(command + j) != NUL) {    /* Loop on string characters */
  1096.     parms[k++] = strg0 + i;
  1097.     while (*(command + j) == ' ')
  1098.         ++j;
  1099.     while (*(command + j) != ' ' && *(command + j) != NUL) {
  1100.         if (*(command + j) == '"')    /* Get quoted string */
  1101.         for (*(strg0 + (i++)) = *(command + (j++));
  1102.              *(command + j) != '"';
  1103.              *(strg0 + (i++)) = *(command + (j++)));
  1104.         *(strg0 + (i++)) = *(command + (j++));
  1105.     }
  1106.     *(strg0 + (i++)) = NUL;    /* NUL terminate every token */
  1107.     }
  1108.     parms[k] = NUL;
  1109.  
  1110.     for (k = strlen(strg0) - 1; k >= 0; --k)    /* Convert to lower case */
  1111.     *(strg0 + k) >= 'A' && *(strg0 + k) <= 'Z' ? *(strg0 + k) |= 32 : *(strg0 + k);
  1112. }
  1113.  
  1114. # endif /* AMIGA_AC_5 */
  1115.  
  1116.  
  1117. # if defined(READLINE) || defined(GNU_READLINE)
  1118. /* keep some compilers happy */
  1119. static char *rlgets __PROTO((char *s, int n, char *prompt));
  1120.  
  1121. static char * rlgets(s, n, prompt)
  1122. char *s;
  1123. int n;
  1124. char *prompt;
  1125. {
  1126.     static char *line = (char *) NULL;
  1127.     static int leftover = -1;    /* index of 1st char leftover from last call */
  1128.  
  1129.     if (leftover == -1) {
  1130.     /* If we already have a line, first free it */
  1131.     if (line != (char *) NULL) {
  1132.         free(line);
  1133.         line = NULL;
  1134.         /* so that ^C or int_error during readline() does
  1135.          * not result in line being free-ed twice */
  1136.     }
  1137.     line = readline((interactive) ? prompt : "");
  1138.     leftover = 0;
  1139.     /* If it's not an EOF */
  1140.     if (line && *line)
  1141.         add_history(line);
  1142.     }
  1143.     if (line) {
  1144.     safe_strncpy(s, line + leftover, n);
  1145.     leftover += strlen(s);
  1146.     if (line[leftover] == NUL)
  1147.         leftover = -1;
  1148.     return s;
  1149.     }
  1150.     return NULL;
  1151. }
  1152. # endif /* READLINE || GNU_READLINE */
  1153.  
  1154.  
  1155. # if defined(MSDOS) || defined(_Windows) || defined(DOS386)
  1156. static void do_shell()
  1157. {
  1158.     register char *comspec;
  1159.     if ((comspec = getenv("COMSPEC")) == (char *) NULL)
  1160.     comspec = "\\command.com";
  1161. #  ifdef _Windows
  1162.     if (WinExec(comspec, SW_SHOWNORMAL) <= 32)
  1163. #  else
  1164. #   ifdef DJGPP
  1165.     if (system(comspec) == -1)
  1166. #   else
  1167.     if (spawnl(P_WAIT, comspec, NULL) == -1)
  1168. #   endif /* !DJGPP */
  1169. #  endif /* !_Windows */
  1170.     os_error("unable to spawn shell", NO_CARET);
  1171. }
  1172.  
  1173. # else /* !MSDOS */
  1174.  
  1175. /* plain old Unix */
  1176.  
  1177. #  ifdef AMIGA_SC_6_1
  1178. static void do_shell()
  1179. {
  1180.     register char *shell;
  1181.     if (!(shell = getenv("SHELL")))
  1182.     shell = SHELL;
  1183.  
  1184.     if (system(shell))
  1185.     os_error("system() failed", NO_CARET);
  1186.  
  1187.     (void) putc('\n', stderr);
  1188. }
  1189.  
  1190. #  else /* !AMIGA_SC_6_1 */
  1191.  
  1192. #   ifdef OS2
  1193. static void do_shell()
  1194. {
  1195.     register char *shell;
  1196.     if (!(shell = getenv("SHELL")) && !(shell = getenv("COMSPEC")))
  1197.     shell = SHELL;
  1198.  
  1199.     if (system(shell) == -1)
  1200.     os_error("system() failed", NO_CARET);
  1201.  
  1202.     (void) putc('\n', stderr);
  1203. }
  1204. #   else /* !OS2 */
  1205.  
  1206. #define EXEC "exec "
  1207. static void do_shell()
  1208. {
  1209.     static char exec[100] = EXEC;
  1210.     register char *shell;
  1211.     if (!(shell = getenv("SHELL")))
  1212.     shell = SHELL;
  1213.  
  1214.     if (system(safe_strncpy(&exec[sizeof(EXEC) - 1], shell,
  1215.                sizeof(exec) - sizeof(EXEC) - 1)))
  1216.     os_error("system() failed", NO_CARET);
  1217.  
  1218.     (void) putc('\n', stderr);
  1219. }
  1220.  
  1221. #   endif /* !OS2 */
  1222. #  endif /* !AMIGA_SC_6_1 */
  1223. # endif /* !MSDOS */
  1224.  
  1225. /* read from stdin, everything except VMS */
  1226.  
  1227. # if !defined(READLINE) && !defined(GNU_READLINE)
  1228. #  if (defined(MSDOS) || defined(DOS386)) && !defined(_Windows) && !defined(__EMX__) && !defined(DJGPP)
  1229.  
  1230. /* if interactive use console IO so CED will work */
  1231.  
  1232. #define PUT_STRING(s) cputs(s)
  1233. #define GET_STRING(s,l) ((interactive) ? cgets_emu(s,l) : fgets(s,l,stdin))
  1234.  
  1235. #   ifdef __TURBOC__
  1236. /* cgets implemented using dos functions */
  1237. /* Maurice Castro 22/5/91 */
  1238. static char *doscgets __PROTO((char *));
  1239.  
  1240. static char *doscgets(s)
  1241. char *s;
  1242. {
  1243.     long datseg;
  1244.  
  1245.     /* protect and preserve segments - call dos to do the dirty work */
  1246.     datseg = _DS;
  1247.  
  1248.     _DX = FP_OFF(s);
  1249.     _DS = FP_SEG(s);
  1250.     _AH = 0x0A;
  1251.     geninterrupt(33);
  1252.     _DS = datseg;
  1253.  
  1254.     /* check for a carriage return and then clobber it with a null */
  1255.     if (s[s[1] + 2] == '\r')
  1256.     s[s[1] + 2] = 0;
  1257.  
  1258.     /* return the input string */
  1259.     return (&(s[2]));
  1260. }
  1261. #   endif /* __TURBOC__ */
  1262.  
  1263. #   ifdef __ZTC__
  1264. void cputs(char *s)
  1265. {
  1266.     register int i = 0;
  1267.     while (s[i] != NUL)
  1268.     bdos(0x02, s[i++], NULL);
  1269. }
  1270.  
  1271. char *cgets(char *s)
  1272. {
  1273.     bdosx(0x0A, s, NULL);
  1274.  
  1275.     if (s[s[1] + 2] == '\r')
  1276.     s[s[1] + 2] = 0;
  1277.  
  1278.     /* return the input string */
  1279.     return (&(s[2]));
  1280. }
  1281. #   endif /* __ZTC__ */
  1282.  
  1283. /* emulate a fgets like input function with DOS cgets */
  1284. char *cgets_emu(str, len)
  1285. char *str;
  1286. int len;
  1287. {
  1288.     static char buffer[128] = "";
  1289.     static int leftover = 0;
  1290.  
  1291.     if (buffer[leftover] == NUL) {
  1292.     buffer[0] = 126;
  1293. #   ifdef __TURBOC__
  1294.     doscgets(buffer);
  1295. #   else
  1296.     cgets(buffer);
  1297. #   endif
  1298.     fputc('\n', stderr);
  1299.     if (buffer[2] == 26)
  1300.         return NULL;
  1301.     leftover = 2;
  1302.     }
  1303.     safe_strncpy(str, buffer + leftover, len);
  1304.     leftover += strlen(str);
  1305.     return str;
  1306. }
  1307. #  else /* !plain DOS */
  1308.  
  1309. #   define PUT_STRING(s) fputs(s, stderr)
  1310. #   define GET_STRING(s,l) fgets(s, l, stdin)
  1311.  
  1312. #  endif /* !plain DOS */
  1313. # endif /* !READLINE && !GNU_READLINE) */
  1314.  
  1315. /* Non-VMS version */
  1316. static int read_line(prompt)
  1317. char *prompt;
  1318. {
  1319.     int start = 0;
  1320.     TBOOLEAN more = FALSE;
  1321.     int last = 0;
  1322.  
  1323. # if !defined(READLINE) && !defined(GNU_READLINE)
  1324.     if (interactive)
  1325.     PUT_STRING(prompt);
  1326. # endif /* READLINE */
  1327.     do {
  1328.     /* grab some input */
  1329. # if defined(READLINE) || defined(GNU_READLINE)
  1330.     if (((interactive)
  1331.          ? rlgets(&(input_line[start]), input_line_len - start,
  1332.               ((more) ? "> " : prompt))
  1333.          : fgets(&(input_line[start]), input_line_len - start, stdin))
  1334.         == (char *) NULL) {
  1335. # else /* !(READLINE || GNU_READLINE) */
  1336.     if (GET_STRING(&(input_line[start]), input_line_len - start)
  1337.         == (char *) NULL) {
  1338. # endif /* !(READLINE || GNU_READLINE) */
  1339.         /* end-of-file */
  1340.         if (interactive)
  1341.         (void) putc('\n', stderr);
  1342.         input_line[start] = NUL;
  1343.         inline_num++;
  1344.         if (start > 0)    /* don't quit yet - process what we have */
  1345.         more = FALSE;
  1346.         else
  1347.         return (1);    /* exit gnuplot */
  1348.     } else {
  1349.         /* normal line input */
  1350.         last = strlen(input_line) - 1;
  1351.         if (last >= 0) {
  1352.         if (input_line[last] == '\n') {        /* remove any newline */
  1353.             input_line[last] = NUL;
  1354.             /* Watch out that we don't backup beyond 0 (1-1-1) */
  1355.             if (last > 0)
  1356.             --last;
  1357.         } else if (last + 2 >= input_line_len) {
  1358.             extend_input_line();
  1359.             start = last + 1;
  1360.             more = TRUE;
  1361.             continue;    /* read rest of line, don't print "> " */
  1362.         }
  1363.         if (input_line[last] == '\\') {        /* line continuation */
  1364.             start = last;
  1365.             more = TRUE;
  1366.         } else
  1367.             more = FALSE;
  1368.         } else
  1369.         more = FALSE;
  1370.     }
  1371. # if !defined(READLINE) && !defined(GNU_READLINE)
  1372.     if (more && interactive)
  1373.         PUT_STRING("> ");
  1374. # endif
  1375.     } while (more);
  1376.     return (0);
  1377. }
  1378. #endif /* !VMS */
  1379.  
  1380. #ifdef _Windows
  1381. /* there is a system like call on MS Windows but it is a bit difficult to 
  1382.    use, so we will invoke the command interpreter and use it to execute the 
  1383.    commands */
  1384. static int winsystem(char *s)
  1385. {
  1386.     LPSTR comspec;
  1387.     LPSTR execstr;
  1388.     LPSTR p;
  1389.  
  1390.     /* get COMSPEC environment variable */
  1391. # ifdef WIN32
  1392.     char envbuf[81];
  1393.     GetEnvironmentVariable("COMSPEC", envbuf, 80);
  1394.     if (*envbuf == NUL)
  1395.     comspec = "\\command.com";
  1396.     else
  1397.     comspec = envbuf;
  1398. # else
  1399.     p = GetDOSEnvironment();
  1400.     comspec = "\\command.com";
  1401.     while (*p) {
  1402.     if (!strncmp(p, "COMSPEC=", 8)) {
  1403.         comspec = p + 8;
  1404.         break;
  1405.     }
  1406.     p += strlen(p) + 1;
  1407.     }
  1408. # endif
  1409.     /* if the command is blank we must use command.com */
  1410.     p = s;
  1411.     while ((*p == ' ') || (*p == '\n') || (*p == '\r'))
  1412.     p++;
  1413.     if (*p == NUL) {
  1414.     WinExec(comspec, SW_SHOWNORMAL);
  1415.     } else {
  1416.     /* attempt to run the windows/dos program via windows */
  1417.     if (WinExec(s, SW_SHOWNORMAL) <= 32) {
  1418.         /* attempt to run it as a dos program from command line */
  1419.         execstr = (char *) malloc(strlen(s) + strlen(comspec) + 6);
  1420.         strcpy(execstr, comspec);
  1421.         strcat(execstr, " /c ");
  1422.         strcat(execstr, s);
  1423.         WinExec(execstr, SW_SHOWNORMAL);
  1424.         free(execstr);
  1425.     }
  1426.     }
  1427.  
  1428.     /* regardless of the reality return OK - the consequences of */
  1429.     /* failure include shutting down Windows */
  1430.     return (0);            /* success */
  1431. }
  1432. #endif /* _Windows */
  1433.  
  1434.